#![allow(warnings)]
use std::fmt;

use crate::rtda::Object;


#[derive(Clone)]
pub enum ArrayObject {
    Byte(Vec<i8>),
    Short(Vec<i16>),
    Int(Vec<i32>),
    Long(Vec<i64>),
    Float(Vec<f32>),
    Double(Vec<f64>),
    Char(Vec<u16>),
    Object(Vec<Option<*mut Object>>),
}

impl ArrayObject {

    pub fn bytes(&mut self) -> &mut Vec<i8> {
        match self {
            Self::Byte(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn get_bytes(&self) -> &Vec<i8> {
        match self {
            Self::Byte(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn shorts(&mut self) -> &mut Vec<i16> {
        match self {
            Self::Short(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn get_shorts(&self) -> &Vec<i16> {
        match self {
            Self::Short(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn ints(&mut self) -> &mut Vec<i32> {
        match self {
            Self::Int(v) => v,
            _ => panic!("type mismatch")
        }
    } 
    
    pub fn get_ints(&self) -> &Vec<i32> {
        match self {
            Self::Int(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn longs(&mut self) -> &mut Vec<i64> {
        match self {
            Self::Long(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn get_longs(&self) -> &Vec<i64> {
        match self {
            Self::Long(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn floats(&mut self) -> &mut Vec<f32> {
        match self {
            Self::Float(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn get_floats(&self) -> &Vec<f32> {
        match self {
            Self::Float(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn doubles(&mut self) -> &mut Vec<f64> {
        match self {
            Self::Double(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn get_doubles(&self) -> &Vec<f64> {
        match self {
            Self::Double(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn chars(&mut self) -> &mut Vec<u16> {
        match self {
            Self::Char(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn get_chars(&self) -> &Vec<u16> {
        match self {
            Self::Char(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn refs(&mut self) -> &mut Vec<Option<*mut Object>> {
        match self {
            Self::Object(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn get_refs(&self) -> &Vec<Option<*mut Object>> {
        match self {
            Self::Object(v) => v,
            _ => panic!("type mismatch")
        }
    } 

    pub fn array_length(&self) -> usize {
        match self {
            Self::Byte(v) => v.len(),
            Self::Short(v) => v.len(),
            Self::Int(v) => v.len(),
            Self::Long(v) => v.len(),
            Self::Float(v) => v.len(),
            Self::Double(v) => v.len(),
            Self::Char(v) => v.len(),
            Self::Object(v) => v.len(),
        }
    }

    pub fn array_copy(src: *mut Object, dest: *mut Object, src_pos: usize, dest_pos: usize, length: usize) {
        unsafe {
            match ({ &mut *src }.array(), { &mut *dest }.array()) {
                (Self::Byte(s), Self::Byte(d)) => {
                    let mut _src = &mut s[src_pos..src_pos+length];
                    let mut _dest = &mut d[dest_pos..dest_pos+length];
                    _dest.copy_from_slice(_src);
                },
                (Self::Short(s), Self::Short(d)) => {
                    let mut _src = &mut s[src_pos..src_pos+length];
                    let mut _dest = &mut d[dest_pos..dest_pos+length];
                    _dest.copy_from_slice(_src);
                },
                (Self::Int(s), Self::Int(d)) => {
                    let mut _src = &mut s[src_pos..src_pos+length];
                    let mut _dest = &mut d[dest_pos..dest_pos+length];
                    _dest.copy_from_slice(_src);
                },
                (Self::Long(s), Self::Long(d)) => {
                    let mut _src = &mut s[src_pos..src_pos+length];
                    let mut _dest = &mut d[dest_pos..dest_pos+length];
                    _dest.copy_from_slice(_src);
                },
                (Self::Float(s), Self::Float(d)) => {
                    let mut _src = &mut s[src_pos..src_pos+length];
                    let mut _dest = &mut d[dest_pos..dest_pos+length];
                    _dest.copy_from_slice(_src);
                },
                (Self::Double(s), Self::Double(d)) => {
                    let mut _src = &mut s[src_pos..src_pos+length];
                    let mut _dest = &mut d[dest_pos..dest_pos+length];
                    _dest.copy_from_slice(_src);
                },
                (Self::Char(s), Self::Char(d)) => {
                    let mut _src = &mut s[src_pos..src_pos+length];
                    let mut _dest = &mut d[dest_pos..dest_pos+length];
                    _dest.copy_from_slice(_src);
                },
                (Self::Object(s), Self::Object(d)) => {
                    let mut _src = &mut s[src_pos..src_pos+length];
                    let mut _dest = &mut d[dest_pos..dest_pos+length];
                    _dest.copy_from_slice(_src);
                },
                _ => panic!("array_copy: type mismatch")
            }
        }
    }
}

impl fmt::Display for ArrayObject {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let s = match self {
            Self::Byte(v) => format!("Byte: {:?}", v),
            Self::Short(v) => format!("Short: {:?}", v),
            Self::Int(v) => format!("Int: {:?}", v),
            Self::Long(v) => format!("Long: {:?}", v),
            Self::Float(v) => format!("Float: {:?}", v),
            Self::Double(v) => format!("Double: {:?}", v),
            Self::Char(v) => format!("Char: {:?}", v),
            Self::Object(v) => format!("Object: len {}", v.len()),
        };
        write!(f, "{}", s)
    }
}